home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyc (Python 1.5)
-
- '''
- Performance Data Helper (PDH) Query Classes
-
- Wrapper classes for end-users and high-level access to the PDH query
- mechanisms. PDH is a win32-specific mechanism for accessing the
- performance data made available by the system. The Python for Windows
- PDH module does not implement the "Registry" interface, implementing
- the more straightforward Query-based mechanism.
-
- The basic idea of a PDH Query is an object which can query the system
- about the status of any number of "counters." The counters are paths
- to a particular piece of performance data. For instance, the path
- \'\\Memory\\Available Bytes\' describes just about exactly what it says
- it does, the amount of free memory on the default computer expressed
- in Bytes. These paths can be considerably more complex than this,
- but part of the point of this wrapper module is to hide that
- complexity from the end-user/programmer.
-
- EXAMPLE: A more complex Path
- \t\'\\\\RAISTLIN\\PhysicalDisk(_Total)\\Avg. Disk Bytes/Read\'
- \tRaistlin --> Computer Name
- \tPhysicalDisk --> Object Name
- \t_Total --> The particular Instance (in this case, all instances, i.e. all drives)
- \tAvg. Disk Bytes/Read --> The piece of data being monitored.
-
- EXAMPLE: Collecting Data with a Query
- \tAs an example, the following code implements a logger which allows the
- \tuser to choose what counters they would like to log, and logs those
- \tcounters for 30 seconds, at two-second intervals.
- \t
- \tquery = Query()
- \tquery.addcounterbybrowsing()
- \tquery.collectdatafor(30,2)
- \t
- \tThe data is now stored in a list of lists as:
- \tquery.curresults
- \t
- \tThe counters(paths) which were used to collect the data are:
- \tquery.curpaths
- \t
- \tYou can use the win32pdh.ParseCounterPath(path) utility function
- \tto turn the paths into more easily read values for your task, or
- \twrite the data to a file, or do whatever you want with it.
-
- OTHER NOTABLE METHODS:
- \tquery.collectdatawhile(period) # start a logging thread for collecting data
- \tquery.collectdatawhile_stop() # signal the logging thread to stop logging
- \tquery.collectdata() # run the query only once
- \tquery.addperfcounter(object, counter, machine=None) # add a standard performance counter
- \tquery.addinstcounter(object, counter,machine=None,objtype = \'Process\',volatile=1,format = win32pdh.PDH_FMT_LONG) # add a possibly volatile counter
-
- ### Known bugs and limitations ###
- Due to a problem with threading under the PythonWin interpreter, there
- will be no data logged if the PythonWin window is not the foreground
- application. Workaround: scripts using threading should be run in the
- python.exe interpreter.
-
- The volatile-counter handlers are possibly buggy, they haven\'t been
- tested to any extent. The wrapper Query makes it safe to pass invalid
- paths (a -1 will be returned, or the Query will be totally ignored,
- depending on the missing element), so you should be able to work around
- the error by including all possible paths and filtering out the -1\'s.
-
- There is no way I know of to stop a thread which is currently sleeping,
- so you have to wait until the thread in collectdatawhile is activated
- again. This might become a problem in situations where the collection
- period is multiple minutes (or hours, or whatever).
-
- Should make the win32pdh.ParseCounter function available to the Query
- classes as a method or something similar, so that it can be accessed
- by programmes that have just picked up an instance from somewhere.
-
- Should explicitly mention where QueryErrors can be raised, and create a
- full test set to see if there are any uncaught win32api.error\'s still
- hanging around.
-
- When using the python.exe interpreter, the addcounterbybrowsing-
- generated browser window is often hidden behind other windows. No known
- workaround other than Alt-tabing to reach the browser window.
-
- ### Other References ###
- The win32pdhutil module (which should be in the %pythonroot%/win32/lib
- directory) provides quick-and-dirty utilities for one-off access to
- variables from the PDH. Almost everything in that module can be done
- with a Query object, but it provides task-oriented functions for a
- number of common one-off tasks.
-
- If you can access the MS Developers Network Library, you can find
- information about the PDH API as MS describes it. In general the
- Python version of the API is just a wrapper around the Query-based
- version of this API (as far as I can see), so you can learn what
- you need to from there. From what I understand, the MSDN Online
- resources are available for the price of signing up for them. I can\'t
- guarantee how long that\'s supposed to last. (Or anything for that
- matter).
- http://premium.microsoft.com/isapi/devonly/prodinfo/msdnprod/msdnlib.idc?theURL=/msdn/library/sdkdoc/perfdata_4982.htm
-
- The eventual plan is for my (Mike Fletcher\'s) Starship account to include
- a section on NT Administration, and the Query is the first project
- in this plan. There should be an article describing the creation of
- a simple logger there, but the example above is 90% of the work of
- that project, so don\'t sweat it if you don\'t find anything there.
- (currently the account hasn\'t been set up).
- http://starship.skyport.net/crew/mcfletch/
-
- If you need to contact me immediately, (why I can\'t imagine), you can
- email me at mcfletch@golden.net, or just post your question to the
- Python newsgroup with a catchy subject line.
- news:comp.lang.python
-
- ### Other Stuff ###
- The Query classes are by Mike Fletcher, with the working code
- being corruptions of Mark Hammonds win32pdhutil module.
-
- Use at your own risk, no warranties, no guarantees, no assurances,
- if you use it, you accept the risk of using it, etceteras.
-
- '''
- import win32pdh
- import string
- import win32api
- import time
- import thread
- import copy
-
- class BaseQuery:
- """
- \tProvides wrapped access to the Performance Data Helper query
- \tobjects, generally you should use the child class Query
- \tunless you have need of doing weird things :)
-
- \tThis class supports two major working paradigms. In the first,
- \tyou open the query, and run it as many times as you need, closing
- \tthe query when you're done with it. This is suitable for static
- \tqueries (ones where processes being monitored don't disappear).
-
- \tIn the second, you allow the query to be opened each time and
- \tclosed afterward. This causes the base query object to be
- \tdestroyed after each call. Suitable for dynamic queries (ones
- \twhich watch processes which might be closed while watching.)
- \t"""
-
- def __init__(self, paths = None):
- """
- \t\tThe PDH Query object is initialised with a single, optional
- \t\tlist argument, that must be properly formatted PDH Counter
- \t\tpaths. Generally this list will only be provided by the class
- \t\twhen it is being unpickled (removed from storage). Normal
- \t\tuse is to call the class with no arguments and use the various
- \t\taddcounter functions (particularly, for end user's, the use of
- \t\taddcounterbybrowsing is the most common approach) You might
- \t\twant to provide the list directly if you want to hard-code the
- \t\telements with which your query deals (and thereby avoid the
- \t\toverhead of unpickling the class).
- \t\t"""
- self.counters = []
- if paths:
- self.paths = paths
- else:
- self.paths = []
- self._base = None
- self.active = 0
- self.curpaths = []
-
-
- def addcounterbybrowsing(self, flags = win32pdh.PERF_DETAIL_WIZARD, windowtitle = 'Python Browser'):
- '''
- \t\tAdds possibly multiple paths to the paths attribute of the query,
- \t\tdoes this by calling the standard counter browsing dialogue. Within
- \t\tthis dialogue, find the counter you want to log, and click: Add,
- \t\trepeat for every path you want to log, then click on close. The
- \t\tpaths are appended to the non-volatile paths list for this class,
- \t\tsubclasses may create a function which parses the paths and decides
- \t\t(via heuristics) whether to add the path to the volatile or non-volatile
- \t\tpath list.
- \t\te.g.:
- \t\t\tquery.addcounter()
- \t\t'''
- win32pdh.BrowseCounters(None, 0, self.paths.append, flags, windowtitle)
-
-
- def rawaddcounter(self, object, counter, instance = None, inum = -1, machine = None):
- '''
- \t\tAdds a single counter path, without catching any exceptions.
- \t\t
- \t\tSee addcounter for details.
- \t\t'''
- path = win32pdh.MakeCounterPath((machine, object, instance, None, inum, counter))
- self.paths.append(path)
-
-
- def addcounter(self, object, counter, instance = None, inum = -1, machine = None):
- """
- \t\tAdds a single counter path to the paths attribute. Normally
- \t\tthis will be called by a child class' speciality functions,
- \t\trather than being called directly by the user. (Though it isn't
- \t\thard to call manually, since almost everything is given a default)
- \t\tThis method is only functional when the query is closed (or hasn't
- \t\tyet been opened). This is to prevent conflict in multi-threaded
- \t\tquery applications).
- \t\te.g.:
- \t\t\tquery.addcounter('Memory','Available Bytes')
- \t\t"""
- if not (self.active):
-
- try:
- self.rawaddcounter(object, counter, instance, inum, machine)
- return 0
- except win32api.error:
- return -1
-
- else:
- return -1
-
-
- def open(self):
- """
- \t\tBuild the base query object for this wrapper,
- \t\tthen add all of the counters required for the query.
- \t\tRaise a QueryError if we can't complete the functions.
- \t\tIf we are already open, then do nothing.
- \t\t"""
- if not (self.active):
- self.curpaths = copy.copy(self.paths)
-
- try:
- base = win32pdh.OpenQuery()
- for path in self.paths:
-
- try:
- self.counters.append(win32pdh.AddCounter(base, path))
- except win32api.error:
- 0
- 0
- self.paths
- self.counters.append(0)
- except:
- 0
-
-
- self._base = base
- self.active = 1
- return 0
- except:
-
- try:
- self.killbase(base)
- except NameError:
- pass
-
- self.active = 0
- self.curpaths = []
- raise QueryError(self)
-
-
- return 1
-
-
- def killbase(self, base = None):
- """
- \t\t### This is not a public method
- \t\tMission critical function to kill the win32pdh objects held
- \t\tby this object. User's should generally use the close method
- \t\tinstead of this method, in case a sub-class has overridden
- \t\tclose to provide some special functionality.
- \t\t"""
- self._base = None
- counters = self.counters
- self.counters = []
- self.active = 0
-
- try:
- map(win32pdh.RemoveCounter, counters)
- except:
- pass
-
-
- try:
- win32pdh.CloseQuery(base)
- except:
- pass
-
- del counters
- del base
-
-
- def close(self):
- '''
- \t\tMakes certain that the underlying query object has been closed,
- \t\tand that all counters have been removed from it. This is
- \t\timportant for reference counting.
- \t\tYou should only need to call close if you have previously called
- \t\topen. The collectdata methods all can handle opening and
- \t\tclosing the query. Calling close multiple times is acceptable.
- \t\t'''
-
- try:
- self.killbase(self._base)
- except AttributeError:
- self.killbase()
-
-
- __del__ = close
-
- def collectdata(self, format = win32pdh.PDH_FMT_LONG):
- '''
- \t\tReturns the formatted current values for the Query
- \t\t'''
- if self._base:
- return self.collectdataslave(format)
- else:
- self.open()
- temp = self.collectdataslave(format)
- self.close()
- return temp
-
-
- def collectdataslave(self, format = win32pdh.PDH_FMT_LONG):
- '''
- \t\t### Not a public method
- \t\tCalled only when the Query is known to be open, runs over
- \t\tthe whole set of counters, appending results to the temp,
- \t\treturns the values as a list.
- \t\t'''
-
- try:
- win32pdh.CollectQueryData(self._base)
- temp = []
- for counter in self.counters:
- ok = 0
-
- try:
- if counter:
- temp.append(win32pdh.GetFormattedCounterValue(counter, format)[1])
- ok = 1
- except win32api.error:
- 0
- 0
- self.counters
- except:
- 0
-
-
- return temp
- except win32api.error:
- return [
- -1] * len(self.counters)
-
-
-
- def __getinitargs__(self):
- '''
- \t\t### Not a public method
- \t\t'''
- return (self.paths,)
-
-
-
- class Query(BaseQuery):
- '''
- \tPerformance Data Helper(PDH) Query object:
- \t
- \tProvides a wrapper around the native PDH query object which
- \tallows for query reuse, query storage, and general maintenance
- \tfunctions (adding counter paths in various ways being the most
- \tobvious ones).
- \t'''
-
- def __init__(self, *args, **namedargs):
- """
- \t\tThe PDH Query object is initialised with a single, optional
- \t\tlist argument, that must be properly formatted PDH Counter
- \t\tpaths. Generally this list will only be provided by the class
- \t\twhen it is being unpickled (removed from storage). Normal
- \t\tuse is to call the class with no arguments and use the various
- \t\taddcounter functions (particularly, for end user's, the use of
- \t\taddcounterbybrowsing is the most common approach) You might
- \t\twant to provide the list directly if you want to hard-code the
- \t\telements with which your query deals (and thereby avoid the
- \t\toverhead of unpickling the class).
- \t\t"""
- self.volatilecounters = []
- apply(BaseQuery.__init__, (self,) + args, namedargs)
-
-
- def addperfcounter(self, object, counter, machine = None):
- '''
- \t\tA "Performance Counter" is a stable, known, common counter,
- \t\tsuch as Memory, or Processor. The use of addperfcounter by
- \t\tend-users is deprecated, since the use of
- \t\taddcounterbybrowsing is considerably more flexible and general.
- \t\tIt is provided here to allow the easy development of scripts
- \t\twhich need to access variables so common we know them by name
- \t\t(such as Memory|Available Bytes), and to provide symmetry with
- \t\tthe add inst counter method.
- \t\tusage:
- \t\t\tquery.addperfcounter(\'Memory\', \'Available Bytes\')
- \t\tIt is just as easy to access addcounter directly, the following
- \t\thas an identicle effect.
- \t\t\tquery.addcounter(\'Memory\', \'Available Bytes\')
- \t\t'''
- BaseQuery.addcounter(self, object = object, counter = counter)
-
-
- def addinstcounter(self, object, counter, machine = None, objtype = 'Process', volatile = 1, format = win32pdh.PDH_FMT_LONG):
- """
- \t\tThe purpose of using an instcounter is to track particular
- \t\tinstances of a counter object (e.g. a single processor, a single
- \t\trunning copy of a process). For instance, to track all python.exe
- \t\tinstances, you would need merely to ask:
- \t\t\tquery.addinstcounter('python','Virtual Bytes')
- \t\tYou can find the names of the objects and their available counters
- \t\tby doing an addcounterbybrowsing() call on a query object (or by
- \t\tlooking in performance monitor's add dialog.)
- \t\t
- \t\tBeyond merely rearranging the call arguments to make more sense,
- \t\tif the volatile flag is true, the instcounters also recalculate
- \t\tthe paths of the available instances on every call to open the
- \t\tquery.
- \t\t"""
- if volatile:
- self.volatilecounters.append((object, counter, machine, objtype, format))
- else:
- self.paths[len(self.paths):] = self.getinstpaths(self, object, counter, machine, objtype, format)
-
-
- def getinstpaths(self, object, counter, machine = None, objtype = 'Process', format = win32pdh.PDH_FMT_LONG):
- '''
- \t\t### Not an end-user function
- \t\tCalculate the paths for an instance object. Should alter
- \t\tto allow processing for lists of object-counter pairs.
- \t\t'''
- (items, instances) = win32pdh.EnumObjectItems(None, None, objtype, -1)
- instances.sort()
-
- try:
- cur = instances.index(object)
- except ValueError:
- return []
-
- temp = [
- object]
-
- try:
- while instances[cur + 1] == object:
- temp.append(object)
- cur = cur + 1
- except IndexError:
- pass
-
- paths = []
- for ind in range(len(temp)):
- paths.append(win32pdh.MakeCounterPath((machine, 'Process', object, None, ind, counter)))
-
- return paths
-
-
- def open(self, *args, **namedargs):
- '''
- \t\tExplicitly open a query:
- \t\tWhen you are needing to make multiple calls to the same query,
- \t\tit is most efficient to open the query, run all of the calls,
- \t\tthen close the query, instead of having the collectdata method
- \t\tautomatically open and close the query each time it runs.
- \t\tThere are currently no arguments to open.
- \t\t'''
- apply(BaseQuery.open, (self,) + args, namedargs)
- paths = []
- for tup in self.volatilecounters:
- paths[len(paths):] = apply(self.getinstpaths, tup)
-
- for path in paths:
-
- try:
- self.counters.append(win32pdh.AddCounter(self._base, path))
- self.curpaths.append(path)
- except win32api.error:
- 0
- 0
- paths
- except:
- 0
-
-
-
-
- def collectdatafor(self, totalperiod, period = 1):
- '''
- \t\tNon-threaded collection of performance data:
- \t\tThis method allows you to specify the total period for which you would
- \t\tlike to run the Query, and the time interval between individual
- \t\truns. The collected data is stored in query.curresults at the
- \t\t_end_ of the run. The pathnames for the query are stored in
- \t\tquery.curpaths.
- \t\te.g.:
- \t\t\tquery.collectdatafor(30,2)
- \t\tWill collect data for 30seconds at 2 second intervals
- \t\t'''
- tempresults = []
-
- try:
- self.open()
- for ind in xrange(totalperiod / period):
- tempresults.append(self.collectdata())
- time.sleep(period)
-
- self.curresults = tempresults
- finally:
- self.close()
-
-
-
- def collectdatawhile(self, period = 1):
- '''
- \t\tThreaded collection of performance data:
- \t\tThis method sets up a simple semaphor system for signalling
- \t\twhen you would like to start and stop a threaded data collection
- \t\tmethod. The collection runs every period seconds until the
- \t\tsemaphor attribute is set to a non-true value (which normally
- \t\tshould be done by calling query.collectdatawhile_stop() .)
- \t\te.g.:
- \t\t\tquery.collectdatawhile(2)
- \t\t\t# starts the query running, returns control to the caller immediately
- \t\t\t# is collecting data every two seconds.
- \t\t\t# do whatever you want to do while the thread runs, then call:
- \t\t\tquery.collectdatawhile_stop()
- \t\t\t# when you want to deal with the data. It is generally a good idea
- \t\t\t# to sleep for period seconds yourself, since the query will not copy
- \t\t\t# the required data until the next iteration:
- \t\t\ttime.sleep(2)
- \t\t\t# now you can access the data from the attributes of the query
- \t\t\tquery.curresults
- \t\t\tquery.curpaths
- \t\t'''
- self.collectdatawhile_active = 1
- thread.start_new_thread(self.collectdatawhile_slave, (period,))
-
-
- def collectdatawhile_stop(self):
- '''
- \t\tSignals the collectdatawhile slave thread to stop collecting data
- \t\ton the next logging iteration.
- \t\t'''
- self.collectdatawhile_active = 0
-
-
- def collectdatawhile_slave(self, period):
- '''
- \t\t### Not a public function
- \t\tDoes the threaded work of collecting the data and storing it
- \t\tin an attribute of the class.
- \t\t'''
- tempresults = []
-
- try:
- self.open()
- while self.collectdatawhile_active:
- tempresults.append(self.collectdata())
- time.sleep(period)
- self.curresults = tempresults
- finally:
- self.close()
-
-
-
- def __getinitargs__(self):
- return (self.paths,)
-
-
- def __getstate__(self):
- return self.volatilecounters
-
-
- def __setstate__(self, volatilecounters):
- self.volatilecounters = volatilecounters
-
-
-
- class QueryError:
-
- def __init__(self, query):
- self.query = query
-
-
- def __repr__(self):
- return '<Query Error in %s>' % repr(self.query)
-
- __str__ = __repr__
-
-